﻿Public Class HostDesigner
    Private ntList As New List(Of NucleotideEnum)
    Private Sub slNumber_ValueChanged(sender As Object, e As System.Windows.RoutedPropertyChangedEventArgs(Of Double)) Handles slNumber.ValueChanged
        Try
            Dim lens As Integer = Math.Abs(Math.Round(slNumber.Value))
            Dim tb As New Taboo(lens)
            tb.Strong1 = cbStrong.IsChecked
            rtbContainer.Text = lens.ToString + vbCrLf
            Dim cd As New List(Of String)

            If lens > 0 Then
                If slNumber.Value > 0 Then
                    For i As Integer = 0 To 512
                        Dim pair As New NucleotideSequencePair(tb)
                        If Not cd.Contains(pair.F.ToString) Then
                            cd.Add(pair.F.ToString)
                        Else
                            'Stop
                            rtbContainer.AppendText("---------------- Duplicate Waived" + vbCrLf)
                            Continue For
                        End If
                        If Not cd.Contains(pair.R.ToString) Then
                            cd.Add(pair.R.ToString)
                        Else
                            'Stop
                            rtbContainer.AppendText("---------------- Duplicate Waived" + vbCrLf)
                            Continue For
                        End If
                        If pair.F.ToString = pair.R.ToString Then
                            rtbContainer.AppendText("---------------- Palindromic Waived" + vbCrLf)
                            Continue For
                        End If

                        rtbContainer.AppendText(String.Format("{0}F: N5-{1}-3E {0}R: N5-{2}-3E{3}", i.ToString.PadLeft(3, " "), pair.F.ToString, pair.R.ToString, vbCrLf))
                        rtbContainer.AppendText(String.Format("{0}R: E3-{1}-5N {0}F: E3-{2}-5N{3}", i.ToString.PadLeft(3, " "), pair.R.ToReverseString, pair.F.ToReverseString, vbCrLf))
                        'rtbContainer.AppendText(tb.ToString)
                        'rtbContainer.AppendText(vbCrLf)
                    Next
                Else
                    For i As Integer = 0 To 512
                        Dim pair As New NucleotideSequencePair(tb)
                        If Not cd.Contains(pair.F.ToString) Then
                            cd.Add(pair.F.ToString)
                        Else
                            'Stop
                            rtbContainer.AppendText("---------------- Duplicate Waived" + vbCrLf)
                            Continue For
                        End If
                        If Not cd.Contains(pair.R.ToString) Then
                            cd.Add(pair.R.ToString)
                        Else
                            'Stop
                            rtbContainer.AppendText("---------------- Duplicate Waived" + vbCrLf)
                            Continue For
                        End If

                        If pair.F.ToString = pair.R.ToString Then
                            rtbContainer.AppendText("---------------- Palindromic Waived" + vbCrLf)
                            Continue For
                        End If

                        rtbContainer.AppendText(String.Format("{0}F: E5-{1}-3N {0}R: E5-{2}-3N{3}", i.ToString.PadLeft(3, " "), pair.F.ToReverseString, pair.R.ToString, vbCrLf))
                        rtbContainer.AppendText(String.Format("{0}R: N3-{1}-5E {0}F: N3-{2}-5E{3}", i.ToString.PadLeft(3, " "), pair.R.ToReverseString, pair.F.ToString, vbCrLf))
                    Next
                End If
            End If

        Catch ex As Exception

        End Try
    End Sub

 
End Class

Public Enum NucleotideEnum As Byte
    A = 0
    T = 1
    G = 2
    C = 3
    'NA = 16
    'NT = 32
    'NG = 64
    'NC = 128
End Enum
Public Class Nucleotide
    Public N As NucleotideEnum
    Public Sub New()
    End Sub
    Public Sub New(nt As NucleotideEnum)
        N = nt
    End Sub

    Public Shared Function GuidedRandom(banned As Taboo) As NucleotideSequence
        Dim seed As Double = Rnd(Now.ToOADate)
 
    End Function
    Public Shared Function Random() As NucleotideEnum
        Dim seed As Double = Rnd(Now.ToOADate)
        If seed >= 0.0F And seed < 0.25F Then
            Return NucleotideEnum.A
        ElseIf seed >= 0.25F And seed < 0.5F Then
            Return NucleotideEnum.T
        ElseIf seed >= 0.5F And seed < 0.75F Then
            Return NucleotideEnum.G
        Else
            Return NucleotideEnum.C
        End If

    End Function
    Public Function Describe(shift As Integer) As String
        Dim stb As New System.Text.StringBuilder
        stb.Append("".PadLeft(shift, vbTab) + [Enum].GetName(GetType(NucleotideEnum), N))
        stb.Append(" : ")
        stb.AppendLine(Banned.ToString)
        If Followers IsNot Nothing AndAlso Followers.Count > 0 Then
            stb.AppendLine("".PadLeft(shift, vbTab) + "{")
            For Each nx As Nucleotide In Followers
                stb.Append(nx.Describe(shift + 1))
            Next
            stb.AppendLine("".PadLeft(shift, vbTab) + "}")
        End If
        Return stb.ToString
    End Function
    Public Shared Operator =(N1 As Nucleotide, N2 As Nucleotide) As Boolean
        Return N1.N = N2.N
    End Operator
    Public Shared Operator <>(N1 As Nucleotide, N2 As Nucleotide) As Boolean
        Return N1.N <> N2.N
    End Operator
    'Private Shared AG As NucleotideEnum = NucleotideEnum.A Or NucleotideEnum.G
    'Private Shared TC As NucleotideEnum = NucleotideEnum.T Or NucleotideEnum.C
    'Public Shared Operator And(N1 As Nucleotide, N2 As Nucleotide) As Boolean
    '    Return ((N1.N And AG) And (N2.N And TC)) Or ((N2.N And AG) And (N1.N And TC))
    'End Operator
    Public Followers As List(Of Nucleotide)
    Public Sub BuildTaboo(vCount As Integer)
        vCount -= 1
        If vCount > -1 Then
            Me.Followers = New List(Of Nucleotide)
            Me.Followers.AddRange({New Nucleotide(NucleotideEnum.A), New Nucleotide(NucleotideEnum.T), New Nucleotide(NucleotideEnum.G), New Nucleotide(NucleotideEnum.C)})
            For Each fl As Nucleotide In Followers
                fl.BuildTaboo(vCount)
            Next
        End If
    End Sub
    Public Function Clone() As Nucleotide
        Return New Nucleotide(N)
    End Function
    Public Function Avaialbe(ns As NucleotideSequence) As List(Of Nucleotide)
        If ns.Count = 0 Then
            Dim vFollowers As New List(Of Nucleotide)
            For Each fl As Nucleotide In Followers
                If Not fl.Banned Then vFollowers.Add(fl)
            Next
            Return vFollowers
        ElseIf Banned Then
            Return New List(Of Nucleotide)
        Else
            Return Followers(ns(0)).Avaialbe(ns.Skip(1))
        End If
    End Function
    Default Public Property Value(ns As NucleotideSequence) As Boolean
        Get
            If Banned Then Return True
            If ns.Count = 0 Then
                Return Banned
            Else
                Return Followers(ns(0))(ns.Skip(1))
            End If
        End Get
        Set(value As Boolean)
            If Banned Then Exit Property
            If ns.Count = 0 Then
                Banned = value
            Else
                Followers(ns(0))(ns.Skip(1)) = value
                Dim vcb As Boolean = True
                For Each fl As Nucleotide In Followers
                    vcb = vcb And fl.Banned
                Next
                Banned = vcb
            End If
            If Banned Then
                If Followers IsNot Nothing Then Followers.Clear()
            End If
        End Set
    End Property
    Public Banned As Boolean = False
End Class
Public Class NucleotideSequence
    Inherits List(Of NucleotideEnum)
    Public Shared Operator And(F As NucleotideSequence, R As NucleotideSequence) As Boolean
        If F.Count = R.Count Then
            Dim match As Boolean = False
            Dim ctn As Integer = F.Count - 1
            For i As Integer = 0 To ctn
                If i = ctn Then
                    match = match And (F(i) = R(i))
                Else
                    match = match And (F(i) And R(i))
                End If
            Next
            Return match
        Else
            Return False
        End If
    End Operator
    Public Function Skip(vCount As Integer) As NucleotideSequence
        Dim i As Integer = 0
        Dim ns As New NucleotideSequence
        For i = vCount To Me.Count - 1
            ns.Add(Me(i))
        Next
        Return ns
    End Function
    Public Function Drop(vCount As Integer) As NucleotideSequence
        Dim i As Integer = 0
        Dim ns As New NucleotideSequence
        For i = 0 To Me.Count - 1 - vCount
            ns.Add(Me(i))
        Next
        Return ns
    End Function
    Public Shared Operator Not(ns As NucleotideSequence) As NucleotideSequence
        Dim nc As New NucleotideSequence
        Dim nt As NucleotideEnum
        For i As Integer = ns.Count - 1 To 0 Step -1
            nt = ns(i)
                Select Case nt
                    Case NucleotideEnum.A
                        nc.Add(NucleotideEnum.T)
                    Case NucleotideEnum.G
                        nc.Add(NucleotideEnum.C)
                    Case NucleotideEnum.C
                        nc.Add(NucleotideEnum.G)
                    Case NucleotideEnum.T
                        nc.Add(NucleotideEnum.A)
                End Select
        Next
        Return nc
    End Operator
    Public Shared Operator +(nx As NucleotideEnum, seq As NucleotideSequence) As NucleotideSequence
        Dim v As New NucleotideSequence
        v.Add(nx)
        v.AddRange(seq)
        Return v
    End Operator
    Public Function Related() As NucleotideSequence
        Dim nc As New NucleotideSequence
        Dim nt As NucleotideEnum
        For i As Integer = 0 To Me.Count - 1
            nt = Me(i)
            If i < Me.Count - 1 Then
                Select Case nt
                    Case NucleotideEnum.A
                        nc.Add(NucleotideEnum.A)
                    Case NucleotideEnum.G
                        nc.Add(NucleotideEnum.G)
                    Case NucleotideEnum.C
                        nc.Add(NucleotideEnum.C)
                    Case NucleotideEnum.T
                        nc.Add(NucleotideEnum.T)
                End Select
            Else
                Select Case nt
                    Case NucleotideEnum.A
                        nc.Add(NucleotideEnum.G)
                    Case NucleotideEnum.G
                        nc.Add(NucleotideEnum.A)
                    Case NucleotideEnum.C
                        nc.Add(NucleotideEnum.T)
                    Case NucleotideEnum.T
                        nc.Add(NucleotideEnum.C)
                End Select
            End If
        Next
        Return nc
    End Function
    Public Overrides Function ToString() As String
        Dim stb As New System.Text.StringBuilder
        For Each nt As NucleotideEnum In Me
            stb.Append([Enum].GetName(GetType(NucleotideEnum), nt))
        Next
        Return stb.ToString()
    End Function
    Public Function ToReverseString() As String
        Dim stb As New System.Text.StringBuilder
        For i As Integer = Me.Count - 1 To 0 Step -1
            stb.Append([Enum].GetName(GetType(NucleotideEnum), Me(i)))
        Next
        Return stb.ToString()
    End Function
End Class
Public Class Taboo
    Private vTaboo As New Nucleotide
    Private _Length As Integer
    Public Sub New(vLength As Integer)
        _Length = vLength
        vTaboo.BuildTaboo(vLength)
    End Sub
    Public Property Strong1 As Boolean = True
    Public Sub AddTaboo(tb As NucleotideSequence)
        vTaboo(tb) = True
        Dim nc As NucleotideSequence = Not tb
        vTaboo(nc) = True
        vTaboo(tb.Related) = True
        vTaboo(nc.Related) = True
        If _Strong1 Then
            Dim tbd As NucleotideSequence = tb.Drop(1)
            Dim ncd As NucleotideSequence = nc.Drop(1)
            vTaboo(tbd) = True
            vTaboo(ncd) = True
            Dim tbdr As NucleotideSequence = Not tbd
            Dim ncdr As NucleotideSequence = Not ncd
            vTaboo(NucleotideEnum.A + tbdr) = True
            vTaboo(NucleotideEnum.T + tbdr) = True
            vTaboo(NucleotideEnum.G + tbdr) = True
            vTaboo(NucleotideEnum.C + tbdr) = True
            vTaboo(NucleotideEnum.A + ncdr) = True
            vTaboo(NucleotideEnum.T + ncdr) = True
            vTaboo(NucleotideEnum.G + ncdr) = True
            vTaboo(NucleotideEnum.C + ncdr) = True
        End If
    End Sub
    Public Function IsValid(tb As NucleotideSequence) As Boolean
        Return vTaboo(tb)
    End Function
    Public Function Random() As NucleotideSequence
        Dim i As Integer = 0
        Dim vCurrentSeq As New NucleotideSequence
        While i < _Length
            Dim seed As Single = Rnd(Now.ToOADate)
            Dim av As List(Of Nucleotide) = vTaboo.Avaialbe(vCurrentSeq)
            Dim c As Integer = av.Count
            If c = 0 Then Throw New Exception("没有可用的序列了！")
            vCurrentSeq.Add(av(Math.Floor(c * seed)).N)
            i += 1
        End While
        AddTaboo(vCurrentSeq)
        Return vCurrentSeq
    End Function
    Public Overrides Function ToString() As String
        Return vTaboo.Describe(0)
    End Function
End Class
Public Class NucleotideSequencePair
    Public F As NucleotideSequence
    Public R As NucleotideSequence
    Public Sub New(banned As Taboo)
        F = banned.Random()
        R = Not F
    End Sub
    Public Shared Operator And(NSP1 As NucleotideSequencePair, NSP2 As NucleotideSequencePair) As Boolean
        Return NSP1.F And NSP2.R OrElse NSP1.R And NSP2.R OrElse NSP1.R And NSP2.F OrElse NSP1.R And NSP2.F
    End Operator
End Class

'ATTC
'TAAG

'A=T
'G=C
'G=T
'A=C

'ATT[AG]
'TAAC